package com.codegeek.project.communicate;

import com.alibaba.fastjson.JSONObject;
import com.codegeek.common.utils.DateUtils;
import com.codegeek.framework.ems.EmsServerUtil;
import com.codegeek.framework.mail.MailService;
import com.codegeek.framework.redis.RedisCache;
import com.codegeek.project.monitor.domain.SysOperLog;
import com.codegeek.project.monitor.service.ISysOperLogService;
import com.codegeek.project.slope.domain.*;
import com.codegeek.project.slope.service.*;
import org.apache.logging.log4j.LogManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author wj
 * @ClassName
 * @Description
 * @date 2020-03-19
 */
@Component
public class RedisDBService {
    private static final Logger _logger = LoggerFactory.getLogger(RedisDBService.class);

    public static final org.apache.logging.log4j.Logger logger = LogManager.getLogger("FileUtils");

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ISlopeSensorTypeService slopeSensorTypeService;

    @Autowired
    private ISlopeSensorService slopeSensorService;

    @Autowired
    private ISlopeItemHistoryService slopeItemHistoryService;

    @Autowired
    private ISlopeAlarmService slopeAlarmService;

    @Autowired
    private ISlopeSubscriberService slopeSubscriberService;

    @Autowired
    private ISlopeMonitorItemService slopeMonitorItemService;

    @Autowired
    private ISlopeSubscribeDetailService slopeSubscribeDetailService;

    @Autowired
    private ISlopeDeviceService slopeDeviceService;

    @Autowired
    private ISysOperLogService operLogService;

    @Autowired
    private EmsServerUtil emsServerUtil;

    @Autowired
    private MailService mailService;


    private static final Map<String,Integer> alarmLevelMap=new HashMap<>();

    static final String REDIS_DB_CACHE="redis_db_constant";            //存储一些数据库常用类型值

    static final String CONST_KEY_GNSSTYPEID ="gnssTypeId";          //一些属性键名
    static final String CONST_KEY_INITCHECKED ="initChecked";          //一些属性键名

    static final String REDIS_DB_REALTIME="redis_db_realtime";      //存储一些设备实时值
    static final String REDIS_DB_SENSOR_REALTIME_PREFIX="redis_db_sensor_realtime_";        //传感器实时数据前缀
    static final String REDIS_DB_SENSOR_HISTORY_PREFIX="redis_db_sensor_history_";          //传感器历史数据前缀
    static final String REDIS_DEVICEINFO_PREFIX="redis_deviceInfo_";            //以Imei为键名存储的一些设备信息缓存值，很少修改
    static final String REDIS_DB_DEVICE_REALTIME_PREFIX ="redis_db_device_realtime_";        //传感器实时数据前缀

    /**
     * @title
     * @description 获取GNSS类型
     * @param
     * @return
     * @throws
     */
    public Integer getGNSSTypeId(){
        Map dbCache=getOrCreateDBCache();
        if(dbCache.containsKey(CONST_KEY_GNSSTYPEID)){
            return (Integer) dbCache.get(CONST_KEY_GNSSTYPEID);
        }else{
            SlopeSensorType slopeSensorType= slopeSensorTypeService.selectSlopeSensorTypeByName("GNSS");
            Integer id=1;
            if(slopeSensorType!=null){
                id=slopeSensorType.getSensorTypeId();
            }
            dbCache.put(CONST_KEY_GNSSTYPEID,id);
            redisCache.setCacheMap(REDIS_DB_CACHE,dbCache);
            return  id;
        }
    }

    public Date getSensorUpdateTime(String imei){
        Map sensorRealtime=getOrCreateSensorRealtime(imei);
        return  (Date) sensorRealtime.get("updateTime");
    }

    //刷新传感器实时监测数据
    public void updateSensorRealtime(String imei,Date time,JSONObject valueMap){
        SlopeDevice device = slopeSensorService.selectValidSensorByImei(imei).getDevice();
        device.setState(1);
        slopeDeviceService.updateSlopeDevice(device);
        Map sensorRealtime=getOrCreateSensorRealtime(imei);
        sensorRealtime.put("data",valueMap.toJSONString());
        sensorRealtime.put("updateTime",time);
        saveSensorRealtime(imei,sensorRealtime);
    }

    /**
     * 更新monitor_item的实时值，
     * @param itemId//monitor_item 的列id
     * @param itemValue//检测项的实时值
     */
    void handleUpdateMoniterItem(Long itemId, float itemValue) {
        SlopeMonitorItem slopeMonitorItem = new SlopeMonitorItem();
        slopeMonitorItem.setItemId(itemId);
        slopeMonitorItem.setItemValue(itemValue);
        slopeMonitorItem.setValueTime(new Date());
        slopeMonitorItemService.updateSlopeMonitorItem(slopeMonitorItem);
    }

    //获取监测项实时数据,传参为设备imei号
    public Float getMonitorItemData(String imei,String itemName){
        try {
            Map sensorRealtime = getOrCreateSensorRealtime(imei);
            String strData = (String) sensorRealtime.get("data");
            JSONObject jsonObject=JSONObject.parseObject(strData);
            return jsonObject.getFloat(itemName);
        }catch (Exception e){
            return null;
        }
    }

    //判断设备是否在线
    public boolean isSensorDeviceOnline(String imei){
        try {
            boolean isOnline=false;
            Map sensorRealtime = getOrCreateSensorRealtime(imei);
            Date date = (Date) sensorRealtime.get("updateTime");
            Date date1=new Date();
            long timeSpan= date1.getTime()- date.getTime();
            if(timeSpan<=1000*60*10){
                isOnline=true;
            }
            return isOnline;
        }
        catch (Exception e){
            return false;
        }
    }

    //添加传感器历史数据
    public void addSensorHistoryData(String sensorImei,Date time,JSONObject jsonValues){
        try {
            Map<String,String> sensorHistory=getOrCreateSensorHistory(sensorImei);
            SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
            String strDate=sdf.format(time);
            Calendar calendar=Calendar.getInstance();
            calendar.setTime(time);
            int index= calendar.get(Calendar.HOUR_OF_DAY)*60+calendar.get(Calendar.MINUTE);
            if(sensorHistory!=null){
                JSONObject jsDailyData=JSONObject.parseObject(sensorHistory.get(strDate));
                if(jsDailyData==null){
                    jsDailyData=new JSONObject();
                }
                jsDailyData.put(String.valueOf(index),jsonValues);
                sensorHistory.put(strDate,jsDailyData.toJSONString());
                saveSensorHistory(sensorImei,sensorHistory);
            }
        }catch (Exception e){
        }

    }

    //告警检测
    public int alarmCheck(SlopeMonitorItem item,String deviceName,String deviceNum ,Float itemValue, Long sensorId) {
        try {
            if(item==null||itemValue==null){
                return 0;
            }

            String itemId=String.valueOf(item.getItemId());
            itemValue=Math.abs(itemValue);
            SlopeAlarm alarm = new SlopeAlarm();
            Float thread1 = item.getThreshold1();
            Float thread2 = item.getThreshold2();
            Float thread3 = item.getThreshold3();
            if (itemValue < thread1) { //并未告警
                alarmLevelMap.remove(itemId);
                return 0;
            } else if (itemValue < thread2) {
                alarm.setAlarmLevel(1);
                alarm.setAlarmThreadhold(thread1);
            } else if (itemValue < thread3) {
                alarm.setAlarmLevel(2);
                alarm.setAlarmThreadhold(thread2);
            } else {
                alarm.setAlarmLevel(3);
                alarm.setAlarmThreadhold(thread3);
            }
            alarm.setAlarmTime(new Date());
            alarm.setAlarmItem(item.getItemId());
            alarm.setAlarmValue(itemValue);
            alarm.setAlarmState(0);
            alarm.setCreateTime(new Date());
            alarm.setAlarmSensorId(sensorId);
            int iRet=0;
            //检测是否已告警
            if(alarmLevelMap.containsKey(itemId)){
                Integer lastLevel=alarmLevelMap.get(itemId);
                Integer currentLevel=alarm.getAlarmLevel();
                //告警升级
                if(currentLevel>lastLevel){
                    alarmLevelMap.put(itemId,currentLevel);
                    iRet = slopeAlarmService.insertSlopeAlarm(alarm);
                }
            }else{
                alarmLevelMap.put(itemId,alarm.getAlarmLevel());
                iRet = slopeAlarmService.insertSlopeAlarm(alarm);
            }
            if(iRet>0){
                SlopeSubscriber subscriber = new SlopeSubscriber();
                subscriber.setIsValid("0");
                List<SlopeSubscriber> list  = slopeSubscriberService.selectSlopeSubscriberList(subscriber);
                String content = getWarmMessageInfo(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss",item.getValueTime()),deviceName,deviceNum,item.getItemName(),alarm.getAlarmLevel(),alarm.getAlarmValue(),alarm.getAlarmThreadhold());
                String subscriberUsers = "";
                for(SlopeSubscriber sub:list){
                    int type =  sub.getSubscribeMethod();
                    try {
                        if (type == 1) {
                            //手机
//                            String code= emsServerUtil.sendMessage(sub.getSubscribePhone(), content);
//                            if(!code.equals("200")){
//                                throw new Exception();
//                            }
                        } else if (type == 2) {
                            mailService.sendSimpleMail(sub.getSubscribeEmail(), deviceName + "发生告警", content);
                            //邮箱
                        } else if (type == 0) {
                            //手机和邮箱
//                            String code= emsServerUtil.sendMessage(sub.getSubscribePhone(), content);
                            mailService.sendSimpleMail(sub.getSubscribeEmail(), deviceName + "发生告警", content);
//                            if(!code.equals("200")){
//                                throw new Exception();
//                            }
                        }
                        subscriberUsers += sub.getSubscriberId()+",";
                    }catch (Exception e){
                        SysOperLog log = new SysOperLog();
                        log.setTitle("推送记录");
                        log.setBusinessType(0);
                        log.setMethod("com.coodgeek.project.communicate.RedisDBServuce");
                        log.setOperatorType(1);
                        log.setOperParam("{content:"+content+"}");
                        log.setJsonResult("{msg:'告警发送给"+sub.getSubscribeNickName()+"失败'}");
                        log.setOperTime(new Date());
                        operLogService.insertOperlog(log);
                    }
                }
                if(subscriberUsers.length()!=0){
                    SlopeSubscribeDetail detail = new SlopeSubscribeDetail();
                    detail.setAlarm(alarm);
                    detail.setSendTime(new Date());
                    detail.setMessage(content);
                    detail.setSubscriber(subscriberUsers.substring(0, subscriberUsers.length() - 1));
                    slopeSubscribeDetailService.insertSlopeSubscribeDetail(detail);
                }
            }
            return  iRet;
        }catch (Exception e){
            _logger.info("设备告警业务异常");
            e.printStackTrace();
            logger.error(e);
            return 0;
        }
    }

    //获取传感器监测项历史数据
    public Map getItemHistoryData(String imei,String itemName){
        try {
            Map<String,JSONObject> retMap=new HashMap<>();
            Map<String,String> sensorHistory=getOrCreateSensorHistory(imei);
            for(String date: sensorHistory.keySet()){
                 JSONObject jsonDailyDate=JSONObject.parseObject(sensorHistory.get(date));
                 JSONObject jsDailyItem=new JSONObject();
                 for(String jsTimeIndex:jsonDailyDate.keySet()){
                     if(jsonDailyDate.getJSONObject(jsTimeIndex).containsKey(itemName)){
                         jsDailyItem.put(jsTimeIndex,jsonDailyDate.getJSONObject(jsTimeIndex).getFloat(itemName));
                     }
                 }
                 retMap.put(date,jsDailyItem);
            }
            return  retMap;
        }catch (Exception e){
            e.printStackTrace();
            logger.error(e);
            return  null;
        }
    }

    //转存传感器监测项历史数据
    public void saveItemHistoryData(String imei,SlopeMonitorItem item){
        Map<String,JSONObject> map =  getItemHistoryData(imei,item.getItemName()); //读
        for(String strDate:map.keySet()){
            try {
                JSONObject jsDailyDate = map.get(strDate);
                SlopeItemHistory sih = new SlopeItemHistory();
                Date date = new SimpleDateFormat("yyyy-MM-dd").parse(strDate);
                sih.setDate(date);
                sih.setItemId(item.getItemId());
                SlopeItemHistory ih=slopeItemHistoryService.selectSlopeItemHistoryByItemIdAndDate(item.getItemId(),strDate);
                String[] valueArr = new String[1440];
                if (ih!=null) {
                    String lastArrStr = ih.getItemValueArr();
                    String[] lastArr = lastArrStr.split(",");
                    //兼容以前的版本
                    for (int i = 0; i < lastArr.length && i < 1440; ++i) {
                        valueArr[i] = lastArr[i];
                    }
                }
                //合并数据
                for (String strIndex : jsDailyDate.keySet()) {
                    Float value = jsDailyDate.getFloat(strIndex);
                    int index = Integer.valueOf(strIndex);
                    if (index < 1440) {
                        valueArr[index] = String.valueOf(value);
                    }
                }

                String result = "";
                for (int i = 0; i < 1440; ++i) {
                    if (valueArr[i] != null) {
                        result += String.valueOf(valueArr[i]);
                    } else {
                        result += "null";
                    }

                    if(i!=1439){
                        result+=",";
                    }
                }

                //新增记录
                if(ih==null){
                    ih=new SlopeItemHistory();
                    ih.setDate(date);
                    ih.setItemValueArr(result);
                    ih.setItemId(item.getItemId());
                    slopeItemHistoryService.insertSlopeItemHistory(ih);

                }
                //更新记录
                else{
                    ih.setItemValueArr(result);
                    slopeItemHistoryService.updateSlopeItemHistory(ih);
                }
            }
            catch (Exception e){
            }
        }
//        clearSensorHistory(imei);
    }

    //获取设备信息
    public SlopeSensor getOrCreateDeviceInfo(String imei){
        SlopeSensor slopeSensor= redisCache.getCacheObject(imei);
        if(slopeSensor==null){
            slopeSensor= slopeSensorService.selectValidSensorByImei(imei);
            refreshDeviceInfo(imei,slopeSensor);
        }
        return slopeSensor;
    }

    //刷新设备信息
    public void refreshDeviceInfo(String imei,SlopeSensor slopeSensor){
        redisCache.setCacheObject(REDIS_DEVICEINFO_PREFIX+imei,slopeSensor);
    }

    //清除传感器历史数据
    public void clearSensorHistory(String imei){
        redisCache.deleteObject(REDIS_DB_SENSOR_HISTORY_PREFIX+imei);
    }

    /******Device业务begin******/
    //3分钟自动离线
    public boolean isDeviceOnline(String imei){
        try {
            boolean isOnline=false;
            Map sensorRealtime = getOrCreateDeviceRealtime(imei);
            Date date = (Date) sensorRealtime.get("updateTime");
            Date date1=new Date();
            long timeSpan= date1.getTime()- date.getTime();
            if(timeSpan<=1000*60*3){
                isOnline=true;
            }
            return isOnline;
        }
        catch (Exception e){
            return false;
        }
    }

    //刷新设备实时监测数据
    public void updateDeviceRealtime(String imei,Date time,JSONObject valueMap){
        Map deviceRealtime=getOrCreateSensorRealtime(imei);
        deviceRealtime.put("data",valueMap.toJSONString());
        deviceRealtime.put("updateTime",time);
        saveDeviceRealtime(imei,deviceRealtime);
    }

    //清空设备实时数据
    public void clearDeviceRealtime(String imei){
        redisCache.deleteObject(REDIS_DB_SENSOR_REALTIME_PREFIX+imei);
    }

    //刷新设备心跳
    public  void deviceHeartBeat(String imei){
        Map deviceRealtime=getOrCreateSensorRealtime(imei);
        deviceRealtime.put("updateTime",new Date());
        saveDeviceRealtime(imei,deviceRealtime);
    }

    private Map getOrCreateDeviceRealtime(String imei){
        Map dbCache=redisCache.getCacheMap(REDIS_DB_DEVICE_REALTIME_PREFIX +imei);
        if(dbCache==null){
            dbCache=new HashMap();
            dbCache.put("updateTime",null);
            dbCache.put("data",new JSONObject().toJSONString());
            saveDeviceRealtime(imei,dbCache);
        }
        return dbCache;
    }

    void saveDeviceRealtime(String imei,Map map){
        redisCache.setCacheMap(REDIS_DB_DEVICE_REALTIME_PREFIX+imei,map);
    }
    /******Device业务end******/


    /**
     * @title
     * @description
     * @param
     * @return
     * @throws
     */
    private Map getOrCreateDBCache(){
        Map dbCache=redisCache.getCacheMap(REDIS_DB_CACHE);
        if(dbCache==null){
            dbCache=new HashMap();
            redisCache.setCacheMap(REDIS_DB_CACHE,dbCache);
        }
        return dbCache;
    }

    private Map getOrCreateSensorRealtime(String sensorId){
        Map dbCache=redisCache.getCacheMap(REDIS_DB_SENSOR_REALTIME_PREFIX+sensorId);
        if(dbCache==null){
            dbCache=new HashMap();
            dbCache.put("updateTime",null);
            dbCache.put("data",new JSONObject().toJSONString());
            saveSensorRealtime(sensorId,dbCache);
        }
        return dbCache;
    }

    private void saveSensorRealtime(String sensorId,Map values){
        redisCache.setCacheMap(REDIS_DB_SENSOR_REALTIME_PREFIX+sensorId,values);
    }

    private Map getOrCreateSensorHistory(String sensorId){
        Map dbCache=redisCache.getCacheMap(REDIS_DB_SENSOR_HISTORY_PREFIX+sensorId);
        if(dbCache==null){
            dbCache=new HashMap();
            saveSensorHistory(sensorId,dbCache);
        }
        return dbCache;
    }

    private void saveSensorHistory(String sensorId,Map historys){
        redisCache.setCacheMap(REDIS_DB_SENSOR_HISTORY_PREFIX+sensorId,historys);
    }

    private String getWarmMessageInfo(String warmTime,String deviceName,String deviceNum,String itemName,int alarmLevel,float alarmValue,float threshold){
        return warmTime+"，"+deviceName+"设备，编号"+deviceNum+"，"+itemName+"测项当前处于"+alarmLevel+"级告警，当前监测值"+alarmValue+"，监测阈值"+threshold;
    }

}
